﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

namespace NetMonitor
{
    public partial class Form1 : Form
    {
        #region Attributes

        QT.IO.INIFile SettingFile = new QT.IO.INIFile(GlobalAttrib.IniPath);

        Thread thread = null;
        private delegate void OutTxt(string txt);

        private int TimeOut = 0;
        private int Resp = 0;
        private DateTime dtStart=DateTime.Now;
        private int Count = 0;

        #endregion

        #region Form

        public Form1()
        {
            InitializeComponent();
            InitApp();
        }

        public Form1(string args)
        {
            InitializeComponent();
            InitApp();
            if (string.IsNullOrEmpty(args)) GlobalAttrib.WindowState = "Normal";
            if (args.ToUpper() == "HIDE") GlobalAttrib.WindowState = "Hide";
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            if (GlobalAttrib.WindowState == "Hide")
            {
                this.notifyIcon1.Visible = true;
                this.Hide();
            }
            else
            {
                this.notifyIcon1.Visible = true;
                this.WindowState = FormWindowState.Normal;
            }

            thread = new Thread(new ThreadStart(Monitor));
            if (GlobalAttrib.IsAutoMonitor) this.btnMonitor_Click(new object(), new EventArgs());
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.notifyIcon1.Visible = true;
                this.Hide();
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;

            if (thread.IsAlive)
            {
                DialogResult DResult = MessageBox.Show("是否最小化到任务栏，选择“否”将关闭程序", "系统提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (DResult == DialogResult.Yes)
                {
                    this.notifyIcon1.Visible = true;
                    this.Hide();
                    return;
                }
                else if (DResult == DialogResult.No)
                {
                    if (GlobalAttrib.IsRunning && thread.IsAlive && MessageBox.Show("正在监控网络，确认要强制退出吗?", "系统提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                    {
                        return;
                    }
                }
                else
                {
                    return;
                }

                Application.ExitThread();
            }
            
            e.Cancel = false;
        }

        #endregion

        #region Button

        //启动监控
        private void btnMonitor_Click(object sender, EventArgs e)
        {
            if (GlobalAttrib.IsRunning == false)
            {
                if (!SaveSetting()) return;
                if (!SaveAlarm()) return;

                FileInfo file = new FileInfo(GlobalAttrib.LogFile);
                if (!Directory.Exists(file.DirectoryName))
                {
                    Directory.CreateDirectory(file.DirectoryName);
                }

                GlobalAttrib.IsRunning = true;
                this.btnMonitor.Text = "停止监控";
                this.rtbView.Invoke(new OutTxt(outView), new object[] { "启动监控" });
                this.rtbLogs.Clear();
                TimeOut = 0;
                Resp = 0;
                thread = new Thread(new ThreadStart(Monitor));
                thread.Start();
            }
            else
            {
                try
                {
                    thread.Abort();
                }
                catch (ThreadAbortException)
                {
                }
                GlobalAttrib.IsRunning = false;
                this.btnMonitor.Text = "启动监控";
                this.rtbView.Invoke(new OutTxt(outView), new object[] { "停止监控" });
            }
        }

        //保存配置
        private void btnSaveSetting_Click(object sender, EventArgs e)
        {
            if (!SaveSetting()) return;

            MessageBox.Show("保存成功");
        }

        //保存警报
        private void btnSaveAlarm_Click(object sender, EventArgs e)
        {
            if (!SaveAlarm()) return;

            MessageBox.Show("保存成功");
        }

        #endregion

        #region CheckBox

        private void cbEmail_CheckedChanged(object sender, EventArgs e)
        {
            if (this.cbEmail.Checked) this.gbEmail.Enabled = true;
            else this.gbEmail.Enabled = false;
        }

        private void cbSms_CheckedChanged(object sender, EventArgs e)
        {
            if (this.cbSms.Checked) this.gbSMS.Enabled = true;
            else this.gbSMS.Enabled = false;
        }

        #endregion

        #region NotifyIcon

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.Visible = true;
            this.WindowState = FormWindowState.Normal;
        }

        #endregion

        #region ToolStripMenuItem

        private void toolStripMenuItem_SaveLog_Click(object sender, EventArgs e)
        {
            this.saveFileDialog1.ValidateNames = true;
            this.saveFileDialog1.Filter = "日志文件(*.log)|*.log";
            this.saveFileDialog1.FilterIndex = 2;
            this.saveFileDialog1.DefaultExt = "log";
            this.saveFileDialog1.FileName = DateTime.Now.ToShortDateString().Replace("/","-");
            this.saveFileDialog1.AddExtension = true;
            if (this.saveFileDialog1.ShowDialog() == DialogResult.Cancel)
            {
                return;
            }

            try
            {
                this.rtbLogs.SaveFile(this.saveFileDialog1.FileName, RichTextBoxStreamType.PlainText);
                MessageBox.Show("保存成功");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        #endregion

        #region Thread&Gelegate

        //监控
        private void Monitor()
        {
            if (!TryToIP(this.tbTargetIP.Text, GlobalAttrib.TargetIP)) return;
            dtStart = DateTime.Now;

            try
            {
                while (true)
                {
                    string pingResult = GetPing(GlobalAttrib.TargetIP);
                    this.rtbLogs.Invoke(new OutTxt(outLog), new object[] { pingResult + "\n" });
                    if (TimeOut >= GlobalAttrib.Timeout)
                    {
                        this.rtbView.Invoke(new OutTxt(outView), new object[] { "本机到" + GlobalAttrib.TargetIP + "连续" + GlobalAttrib.Timeout + "次超时" });
                        if (GlobalAttrib.AlarmType == "1" || GlobalAttrib.AlarmType == "10")
                        {
                            MessageBox.Show("本机到" + GlobalAttrib.TargetIP + "的网络连接故障，请立即检查！");
                        }
                        GlobalAttrib.Error = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "监控服务器到" + GlobalAttrib.TargetIP + "的网络连接故障，请立即检查！";
                        TimeOut = 0;
                    }
                    if (Resp >= GlobalAttrib.Response)
                    {
                        this.rtbView.Invoke(new OutTxt(outView), new object[] { "本机到" + GlobalAttrib.TargetIP + "连续" + GlobalAttrib.Response + "次响应时间大于" + GlobalAttrib.ResTime + "毫秒" });
                        if (GlobalAttrib.AlarmType == "1" || GlobalAttrib.AlarmType == "10")
                        {
                            MessageBox.Show("本机到" + GlobalAttrib.TargetIP + "的网络连接不稳定，请尽快检查！");
                        }
                        GlobalAttrib.Error = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "监控服务器到" + GlobalAttrib.TargetIP + "的网络连接不稳定，请尽快检查！";
                        Resp = 0;
                    }
                    if (Count >= GlobalAttrib.Count)
                    {
                        this.rtbView.Invoke(new OutTxt(outView), new object[] { "本机到" + GlobalAttrib.TargetIP + "在" + GlobalAttrib.Time + "分钟内连续" + GlobalAttrib.Count + "次超时" });
                        if (GlobalAttrib.AlarmType == "1" || GlobalAttrib.AlarmType == "10")
                        {
                            MessageBox.Show("本机到" + GlobalAttrib.TargetIP + "的网络连接故障，请尽快检查！");
                        }
                        GlobalAttrib.Error = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "监控服务器到" + GlobalAttrib.TargetIP + "的网络连接故障，请立即检查！";
                        dtStart = DateTime.Now;
                        Count = 0;
                    }

                    if (GlobalAttrib.Error.Length > 0)
                    {
                        if (GlobalAttrib.AlarmEmail) SendEmail();
                        if(GlobalAttrib.AlarmSMS) SendSMS();
                        GlobalAttrib.Error = "";
                    }

                    Thread.Sleep(GlobalAttrib.InterVal * 1000);
                }
            }
            catch (ThreadAbortException)
            {
            }
            catch (InvalidOperationException)
            {
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        //输出到监控richtextbox
        private void outView(string txt)
        {
            this.rtbView.SelectionLength = 0;
            this.rtbView.AppendText("\n");
            this.rtbView.SelectionColor = System.Drawing.Color.Green;
            this.rtbView.AppendText("[" + DateTime.Now.ToLongTimeString() + "]");
            this.rtbView.SelectionColor = System.Drawing.Color.Black;
            this.rtbView.AppendText(txt);
        }

        //输出到日志richtextbox
        private void outLog(string txt)
        {
            this.rtbLogs.SelectionColor = System.Drawing.Color.Black;
            this.rtbLogs.AppendText(txt);
            this.rtbLogs.ScrollToCaret();
            outLogFile(txt);
        }

        //输出到Log文件
        private void outLogFile(string txt)
        {
            FileStream fs = new FileStream(GlobalAttrib.LogFile, FileMode.Append, FileAccess.Write, FileShare.Read);
            StreamWriter text = new StreamWriter(fs);
            text.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] " + txt);
            text.Close();
            fs.Close();
            fs.Dispose();
        }

        //邮件提醒
        private bool SendEmail()
        {
            try
            {
                Mail myMail = new Mail(GlobalAttrib.Smtp, GlobalAttrib.EmailTo, GlobalAttrib.EmailFrom, "服务器故障", GlobalAttrib.Error, GlobalAttrib.EmailID, GlobalAttrib.EmailPass, GlobalAttrib.SmtpPort, false, false);
                myMail.Send();
            }
            catch
            {
                return false;
            }
            return true;
        }

        //短信提醒
        private bool SendSMS()
        {
            try
            {
                string url = string.Format(GlobalAttrib.API, GlobalAttrib.UserName, GlobalAttrib.Password, GlobalAttrib.MobliePhone, GlobalAttrib.Error);
                HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
                httpWebRequest.Method = WebRequestMethods.Http.Get;
                HttpWebResponse webResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                if (webResponse.StatusCode == HttpStatusCode.OK) return true;
                else return false;
            }
            catch
            {
                return false;
            }
        }

        #endregion

        #region Ping

        //域名转换为IP
        public static bool TryToIP(string domain,string IP)
        {
            IP = "";
            IP = domain.Replace("http://", "").Replace("https://", "");
            return true;
        }

        private string GetPing(string Host)
        {
            try
            {
                Ping p1 = new Ping(); 
                PingReply reply = p1.Send(Host);
                StringBuilder sbuilder;
                if (reply.Status == IPStatus.Success)
                {
                    sbuilder = new StringBuilder();
                    sbuilder.Append(string.Format("来自 {0} 的回复：字节={1} 时间={2} TTL={3}", reply.Address.ToString(), reply.Buffer.Length, reply.RoundtripTime, reply.Options.Ttl));
                    if (reply.RoundtripTime > GlobalAttrib.ResTime) Resp++;
                    else Resp = 0;
                    TimeOut = 0;
                    return sbuilder.ToString();
                }
                else if (reply.Status == IPStatus.TimedOut)
                {
                    TimeOut++;
                    Count++;

                    TimeSpan ts = DateTime.Now - dtStart;
                    if (ts.Minutes > GlobalAttrib.Time)
                    {
                        dtStart = DateTime.Now;
                        Count = 0;
                    }

                    return "请求超时";
                }
                else if (reply.Status == IPStatus.DestinationHostUnreachable)
                {
                    TimeOut++;
                    Count++;

                    TimeSpan ts = DateTime.Now - dtStart;
                    if (ts.Minutes > GlobalAttrib.Time)
                    {
                        dtStart = DateTime.Now;
                        Count = 0;
                    }

                    return "来自 " + reply.Address.ToString() + " 的回复：无法访问目标主机";
                }
                else
                {
                    TimeOut++;
                    return "操作失败";
                }
            }
            catch
            {
                return "操作失败";
            }
        }

        #endregion

        #region Setting

        //初始化程序配置
        private void InitApp()
        {
            #region 获取配置信息

            try
            {
                SettingFile.ReadInivalue("Setting", "TargetIP", out GlobalAttrib.TargetIP);
                string InterVal = "";
                string TimeOut = "";
                string Time = "";
                string Count = "";
                string ResTime = "";
                string Response = "";
                SettingFile.ReadInivalue("Setting", "InterVal", out InterVal);
                SettingFile.ReadInivalue("Setting", "Timeout", out TimeOut);
                SettingFile.ReadInivalue("Setting", "Time", out Time);
                SettingFile.ReadInivalue("Setting", "ResTime", out ResTime);
                SettingFile.ReadInivalue("Setting", "Count", out Count);
                SettingFile.ReadInivalue("Setting", "Response", out Response);
                try
                {
                    int.TryParse(InterVal, out GlobalAttrib.InterVal);
                    int.TryParse(TimeOut, out GlobalAttrib.Timeout);
                    int.TryParse(Time, out GlobalAttrib.Time);
                    int.TryParse(ResTime, out GlobalAttrib.ResTime);
                    int.TryParse(Count, out GlobalAttrib.Count);
                    int.TryParse(Response, out GlobalAttrib.Response);
                }
                catch
                {
                }
                string AutoRun = "";
                SettingFile.ReadInivalue("Setting", "AutoRun", out AutoRun);
                GlobalAttrib.IsAutoRun = AutoRun == "1" ? true : false;
                string AutoMonitor = "";
                SettingFile.ReadInivalue("Setting", "AutoMonitor", out AutoMonitor);
                GlobalAttrib.IsAutoMonitor = AutoMonitor == "1" ? true : false;
            }
            catch
            {
                MessageBox.Show("配置初始化失败");
            }

            #endregion

            #region 获取警报配置

            string Password = "";

            try
            {
                SettingFile.ReadInivalue("Alarm", "Type", out GlobalAttrib.AlarmType);
                //Email
                SettingFile.ReadInivalue("Alarm", "SMTP", out GlobalAttrib.Smtp);
                SettingFile.ReadInivalue("Alarm", "Port", out GlobalAttrib.SmtpPort);
                SettingFile.ReadInivalue("Alarm", "EmailID", out GlobalAttrib.EmailID);
                SettingFile.ReadInivalue("Alarm", "EmailPass", out Password);
                GlobalAttrib.EmailPass = QT.Security.AESHelper.AESDecrypt(Password);
                if (GlobalAttrib.EmailPass == null) GlobalAttrib.EmailPass = "";
                SettingFile.ReadInivalue("Alarm", "FromEmail", out GlobalAttrib.EmailFrom);
                SettingFile.ReadInivalue("Alarm", "ToEmail", out GlobalAttrib.EmailTo);
                //短信
                SettingFile.ReadInivalue("Alarm", "API", out GlobalAttrib.API);
                SettingFile.ReadInivalue("Alarm", "UserName", out GlobalAttrib.UserName);
                SettingFile.ReadInivalue("Alarm", "Password", out Password);
                GlobalAttrib.Password = QT.Security.AESHelper.AESDecrypt(Password);
                if (GlobalAttrib.Password == null) GlobalAttrib.Password = "";
                SettingFile.ReadInivalue("Alarm", "Mobile", out GlobalAttrib.MobliePhone);
            }
            catch
            {
                MessageBox.Show("警报初始化失败");
            }

            #endregion

            #region 初始化

            try
            {
                this.tbTargetIP.Text = GlobalAttrib.TargetIP;
                this.nudInterVal.Value = GlobalAttrib.InterVal;
                this.nudTimeout.Value = GlobalAttrib.Timeout;
                this.nudTime.Value = GlobalAttrib.Time;
                this.nudCount.Value = GlobalAttrib.Count;
                this.nudResponse.Value = GlobalAttrib.Response;
                this.nudResponseTime.Value = GlobalAttrib.ResTime;
                this.cbAutoRun.Checked = GlobalAttrib.IsAutoRun;
                this.cbAutoMonitor.Checked = GlobalAttrib.IsAutoMonitor;
                //AlarmType
                string[] Types = GlobalAttrib.AlarmType.Split('|');
                foreach(string type in Types)
                {
                    if(type=="1") this.cbMessBox.Checked=true;
                    if(type=="2") this.cbEmail.Checked=true;
                    if(type=="3") this.cbSms.Checked=true;
                }
                //Email
                this.tbSmtp.Text = GlobalAttrib.Smtp;
                if (string.IsNullOrEmpty(GlobalAttrib.SmtpPort)) this.cbbPort.SelectedIndex = 0;
                else this.cbbPort.SelectedItem = GlobalAttrib.SmtpPort;
                this.tbEmailID.Text = GlobalAttrib.EmailID;
                this.tbEmailFrom.Text = GlobalAttrib.EmailFrom;
                this.tbEmailTo.Text = GlobalAttrib.EmailTo;
                //SMS
                this.tbApi.Text=GlobalAttrib.API;
                this.tbUserName.Text = GlobalAttrib.UserName;
                this.tbMobile.Text = GlobalAttrib.MobliePhone;                
            }
            catch
            {
            }

            #endregion
        }

        //保存配置
        private bool SaveSetting()
        {
            try
            {
                GlobalAttrib.TargetIP = this.tbTargetIP.Text;
                SettingFile.WriteInivalue("Setting", "TargetIP", GlobalAttrib.TargetIP);
                GlobalAttrib.InterVal = (int)this.nudInterVal.Value;
                SettingFile.WriteInivalue("Setting", "InterVal", GlobalAttrib.InterVal.ToString());
                GlobalAttrib.Timeout = (int)this.nudTimeout.Value;
                SettingFile.WriteInivalue("Setting", "Timeout", GlobalAttrib.Timeout.ToString());
                GlobalAttrib.Time = (int)this.nudTime.Value;
                SettingFile.WriteInivalue("Setting", "Time", GlobalAttrib.Time.ToString());
                GlobalAttrib.Count = (int)this.nudCount.Value;
                SettingFile.WriteInivalue("Setting", "Count", GlobalAttrib.Count.ToString());
                GlobalAttrib.ResTime = (int)this.nudResponseTime.Value;
                SettingFile.WriteInivalue("Setting", "ResTime", GlobalAttrib.ResTime.ToString());
                GlobalAttrib.Response = (int)this.nudResponse.Value;
                SettingFile.WriteInivalue("Setting", "Response", GlobalAttrib.Response.ToString());
                GlobalAttrib.IsAutoRun = this.cbAutoRun.Checked;
                SettingFile.WriteInivalue("Setting", "AutoRun", GlobalAttrib.IsAutoRun ? "1" : "0");
                SetAutoRun(GlobalAttrib.IsAutoRun);
                GlobalAttrib.IsAutoMonitor = this.cbAutoMonitor.Checked;
                SettingFile.WriteInivalue("Setting", "AutoMonitor", GlobalAttrib.IsAutoMonitor ? "1" : "0");
            }
            catch
            {
                MessageBox.Show("保存失败");
                return false;
            }

            return true;
        }

        private bool SaveAlarm()
        {
            Regex regex=new Regex(@"[1]\d{10}");
            if (this.cbSms.Checked && !regex.IsMatch(this.tbMobile.Text))
            {
                MessageBox.Show("请输入正确的手机号码");
                return false;
            }

            string AlarmType = "";
            if (this.cbMessBox.Checked)
            {
                GlobalAttrib.AlarmMessgeBox = true;
                AlarmType += "1|";
            }
            if (this.cbEmail.Checked)
            {
                GlobalAttrib.AlarmEmail = true;
                AlarmType += "2|";
            }
            if (this.cbSms.Checked) 
            {
                GlobalAttrib.AlarmSMS = true;
                AlarmType += "3|";
            }
            if(AlarmType.Length>0) AlarmType = AlarmType.Remove(AlarmType.Length - 1);

            try
            {
                //AlarmType
                GlobalAttrib.AlarmType = AlarmType;
                SettingFile.WriteInivalue("Alarm", "Type", GlobalAttrib.AlarmType);
                //Email
                if (this.cbEmail.Checked)
                {
                    GlobalAttrib.Smtp = this.tbSmtp.Text;
                    SettingFile.WriteInivalue("Alarm", "SMTP", GlobalAttrib.Smtp);
                    GlobalAttrib.SmtpPort = this.cbbPort.SelectedItem.ToString();
                    SettingFile.WriteInivalue("Alarm", "Port", GlobalAttrib.SmtpPort);
                    GlobalAttrib.EmailID = this.tbEmailID.Text;
                    SettingFile.WriteInivalue("Alarm", "EmailID", GlobalAttrib.EmailID);
                    if (this.tbEmailPass.Text.Length > 0) GlobalAttrib.EmailPass = this.tbEmailPass.Text;
                    SettingFile.WriteInivalue("Alarm", "EmailPass", QT.Security.AESHelper.AESEncrypt(GlobalAttrib.EmailPass));
                    GlobalAttrib.EmailFrom = this.tbEmailFrom.Text;
                    SettingFile.WriteInivalue("Alarm", "FromEmail", GlobalAttrib.EmailFrom);
                    GlobalAttrib.EmailTo = this.tbEmailTo.Text;
                    SettingFile.WriteInivalue("Alarm", "ToEmail", GlobalAttrib.EmailTo);
                }
                //SMS
                if (this.cbSms.Checked)
                {
                    GlobalAttrib.API = this.tbApi.Text;
                    SettingFile.WriteInivalue("Alarm", "API", GlobalAttrib.API);
                    GlobalAttrib.UserName = this.tbUserName.Text;
                    SettingFile.WriteInivalue("Alarm", "UserName", GlobalAttrib.UserName);
                    if (this.tbPassword.Text.Length > 0) GlobalAttrib.Password = this.tbPassword.Text;
                    SettingFile.WriteInivalue("Alarm", "Password", QT.Security.AESHelper.AESEncrypt(GlobalAttrib.Password));
                    GlobalAttrib.MobliePhone = this.tbMobile.Text;
                    SettingFile.WriteInivalue("Alarm", "Mobile", GlobalAttrib.MobliePhone);
                }
            }
            catch
            {
                MessageBox.Show("保存失败");
                return false;
            }

            return true;
        }

        //设置开机启动
        private bool SetAutoRun(bool b)
        {
            //打开注册表
            RegistryKey regKey = Registry.CurrentUser;
            string SubKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
            RegistryKey optionKey = regKey.OpenSubKey(SubKeyPath, true);
            if (optionKey == null)
            {
                MessageBox.Show(@"注册表打开失败");
                return false;
            }

            //更改健值，设置代理，
            try
            {
                if (b)
                {
                    optionKey.SetValue("NetMonitor", Application.ExecutablePath+" Hide");
                }
                else
                {
                    optionKey.DeleteValue("NetMonitor", false);
                }
            }
            catch
            {
                optionKey.Close();
                MessageBox.Show("代理设置失败");
                return false;
            }

            return true;
        }

        #endregion
    }
}
